package com.one.blocks.rbac.controller.valid;

import com.one.blocks.rbac.constant.RbacValidConstant;
import com.one.blocks.rbac.controller.vo.SysMenuVo;
import com.one.blocks.rbac.domain.SysMenu;
import com.one.blocks.rbac.enums.MenuTypeEnum;
import com.one.blocks.rbac.manager.SysMenuManager;
import com.one.blocks.rbac.manager.SysRoleMenuManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

/**
 * @author linfuxin Created on 2022-08-16 17:41:36
 */
@Slf4j
public class ValidTreeValidatorForSysMenu implements ConstraintValidator<ValidTree, SysMenuVo> {

    @Autowired
    private SysMenuManager sysMenuManager;

    @Autowired
    private SysRoleMenuManager sysRoleMenuManager;

    @Override
    public boolean isValid(SysMenuVo value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        // 插入校验
        if (value.getId() == null) {
            // 校验父子目录类型是否匹配
            SysMenu parentMenu = getAndCacheParentMenu(value);
            return validMenuType(parentMenu, value, context);
        }

        // 更新校验
        SysMenu oldData = getAndCacheOldMenu(value);
        if (oldData.getParentId().equals(value.getParentId())) {
            // 父id未变更且类型不变 => 通过
            if (oldData.getType().equals(value.getType())) {
                return true;
            }

            // 校验父子目录类型是否匹配
            SysMenu parentMenu = getAndCacheParentMenu(value);
            return validMenuType(parentMenu, value, context);
        }

        // 校验父子目录类型是否匹配
        SysMenu parentMenu = getAndCacheParentMenu(value);
        if (!validMenuType(parentMenu, value, context)) {
            return false;
        }

        // 校验是否存在关联数据
        Integer[] existsDataKeys = sysRoleMenuManager.existsDataByKeys(value.getId());
        if (log.isDebugEnabled() && ArrayUtils.isNotEmpty(existsDataKeys)) {
            log.debug("关联数据:{}", existsDataKeys[0]);
        }
        return ArrayUtils.isEmpty(existsDataKeys);
    }

    private SysMenu getAndCacheParentMenu(SysMenuVo value) {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        SysMenu parentMenu = (SysMenu) requestAttributes.getAttribute(RbacValidConstant.SysMenu.REQUEST_KEY_PARENT_MENU, RequestAttributes.SCOPE_REQUEST);
        if (parentMenu == null) {
            parentMenu = value.getParentId() != null ? sysMenuManager.get(value.getParentId()) : null;
        }
        if (parentMenu != null) {
            requestAttributes.setAttribute(RbacValidConstant.SysMenu.REQUEST_KEY_PARENT_MENU, parentMenu, RequestAttributes.SCOPE_REQUEST);
        }
        return parentMenu;
    }

    private SysMenu getAndCacheOldMenu(SysMenuVo value) {
        RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
        SysMenu oldData = (SysMenu) requestAttributes.getAttribute(RbacValidConstant.SysMenu.REQUEST_KEY_MENU, RequestAttributes.SCOPE_REQUEST);
        if (oldData == null) {
            oldData = sysMenuManager.get(value.getId());
        }
        if (oldData != null) {
            requestAttributes.setAttribute(RbacValidConstant.SysMenu.REQUEST_KEY_MENU, oldData, RequestAttributes.SCOPE_REQUEST);
        }
        return oldData;
    }

    @SuppressWarnings("BooleanMethodIsAlwaysInverted")
    private boolean validMenuType(SysMenu parentMenu, SysMenuVo value, ConstraintValidatorContext context) {
        if (parentMenu == null) {
            // 正常类型
            if (MenuTypeEnum.BUTTON.match(value.getType())) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate("button类型节点parentId不能为null").addConstraintViolation();
                return false;
            }
            return true;
        }

        // 父目录 folder => 子目录 folder || menu
        if (MenuTypeEnum.FOLDER.match(parentMenu.getType())) {
            if (!MenuTypeEnum.FOLDER.match(value.getType()) && !MenuTypeEnum.MENU.match(value.getType())) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate("folder父类节点,子节点只能为folder和menu").addConstraintViolation();
                return false;
            }
        }

        // 父目录 menu => 子目录 button
        if (MenuTypeEnum.MENU.match(parentMenu.getType())) {
            if (MenuTypeEnum.BUTTON.match(value.getType())) {
                return true;
            }
            context.disableDefaultConstraintViolation();
            context.buildConstraintViolationWithTemplate("menu父类节点,子节点只能为button").addConstraintViolation();
            return false;
        }

        // 未知类型
        return false;
    }
}
